package com.lap.auth.shared.tools;

import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.experimental.UtilityClass;

@UtilityClass
public class PersistenceUtil {

  /**
   * 针对父-子场景的批量同步（新增/更新/删除）， deleteByIds 只接收 ID 列表（基于 parent 查询得到要比对的 dbList）
   *
   * @param parentId 父节点 id（用于从 DB 查询该父下的现有子记录）
   * @param inputList 前端提交的子记录列表
   * @param idGetter 从子记录中提取主键
   * @param dbFetcherByParent 根据 parentId 查询 DB 中该父下的子记录（List<T>）
   * @param insertBatch 插入逻辑（Consumer<List<T>>）
   * @param updateBatch 更新逻辑（Consumer<List<T>>）
   * @param deleteByIds 删除逻辑（Consumer<List<ID>>） — 仅传 ID
   */
  public static <T, ID, P> void syncChildrenByParent(
      P parentId,
      List<T> inputList,
      Function<T, ID> idGetter,
      Function<P, List<T>> dbFetcherByParent,
      Consumer<List<T>> insertBatch,
      Consumer<List<T>> updateBatch,
      Consumer<List<ID>> deleteByIds) {

    if (inputList == null) {
      inputList = Collections.emptyList();
    }

    // 1. 查询数据库中 parentId 下现有的子记录
    List<T> dbList = dbFetcherByParent.apply(parentId);
    if (dbList == null) {
      dbList = Collections.emptyList();
    }

    // 2. 构建 dbMap: id -> entity
    Map<ID, T> dbMap =
        dbList.stream()
            .filter(Objects::nonNull)
            .collect(Collectors.toMap(idGetter, Function.identity(), (a, b) -> a));

    // 3. 提取 input 中带 id 的 id 集合（用于比较）
    Set<ID> inputIdSet =
        inputList.stream().map(idGetter).filter(Objects::nonNull).collect(Collectors.toSet());

    // 4. 计算三类集合
    List<T> toInsert = new ArrayList<>();
    List<T> toUpdate = new ArrayList<>();

    for (T item : inputList) {
      ID id = idGetter.apply(item);
      if (id == null) {
        // 新增（无 id）
        toInsert.add(item);
      } else if (dbMap.containsKey(id)) {
        // 更新（db 中存在）
        toUpdate.add(item);
      } else {
        // 有 id 但 db 没有（可能是跨父变动、或不一致）——按需视为新增或更新
        // 这里默认作为新增处理（因为 db 中没有该 id）
        toInsert.add(item);
      }
    }

    // 5. 计算需要删除的 ID：dbMap 中的 id，且不在 inputIdSet 中
    List<ID> toDeleteIds =
        dbMap.keySet().stream().filter(id -> !inputIdSet.contains(id)).collect(Collectors.toList());

    // 6. 执行操作（按调用方传入的 Consumer）
    if (!toInsert.isEmpty()) insertBatch.accept(toInsert);
    if (!toUpdate.isEmpty()) updateBatch.accept(toUpdate);
    if (!toDeleteIds.isEmpty()) deleteByIds.accept(toDeleteIds);
  }
}
